#include "cmdFunc.h"
#include "log.h"
#define SQLLEN 4096
//// 删除文件
//int remove_file(const char *file_path) {
//    if (remove(file_path) == 0) {
//        printf("File %s deleted successfully.\n", file_path);
//        return 0;
//    } else {
//        perror("Error deleting file");
//        return -1;
//    }
//}
//
//// 递归删除目录及其内容
//int remove_dir(const char *dir_path) {
//    DIR *d = opendir(dir_path);
//    struct dirent *entry;
//    struct stat statbuf;
//
//    if (!d) {
//        perror("Error opening directory");
//        return -1;
//    }
//
//    while ((entry = readdir(d)) != NULL) {
//        if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
//            char entry_path[PATH_MAX];
//            snprintf(entry_path, PATH_MAX, "%s/%s", dir_path, entry->d_name);
//
//            if (lstat(entry_path, &statbuf) == -1) {
//                perror("Error getting file status");
//                return -1;
//            }
//
//            if (S_ISDIR(statbuf.st_mode)) {
//                if (remove_dir(entry_path) == -1) {
//                    return -1;
//                }
//            } else {
//                if (remove_file(entry_path) == -1) {
//                    return -1;
//                }
//            }
//        }
//    }
//
//    closedir(d);
//
//    if (rmdir(dir_path) == 0) {
//        printf("Directory %s deleted successfully.\n", dir_path);
//        return 0;
//    } else {
//        perror("Error deleting directory");
//        return -1;
//    }
//}




//rm操作,目的：找到在服务器当中是真实路径
//1、找到要删除文件在表中的位置
//1.1根据realPath返回的文件地址以及用户名在表中查找要删除文件的id（第一个目标id）
//1.2查找目标id在表中的哈希值判断是删除文件还是目录
//如果为NULL说明第一个目标id是目录，如果不是，说明是文件
//2、删除文件:
//2.1目标id在表中的哈希值，即这个文件在服务端的文件名
//2.2统计这个哈希值在表中出现的个数，如果只有一个
//把目标id在表中的tomb标志位改成1
//用服务端的固定地址拼接上文件名（哈希值）得到服务器当中是真实路径，然后删除
//如果不止一个
//只把目标id在表中的tomb标志位改成1
//
//3、删除目录：
//3.1找到表中以上一个目标id为pre-id的文件的id（新的目标id），设置这个id的tomb为1
//再次判断找到的id在表中的哈希值，如果为NULL说明是目录，如果不是，说明是文件
//3.2直到找到文件然后调用删除文件

//需要参数：cwd_t *pcwd;cmd_t* cmd;
//MYSQL *conn;


//int delete_file(MYSQL *conn,char *sha1,int netfd){
//    MYSQL_RES *mysql_res;
//    MYSQL_ROW  mysql_row;
//    char query[4096];//构造查询语句
//    //统计哈希值在表中的个数
//    sprintf(query,"select count(*) from filesystem where sha1='%s';",sha1);
//    int ret=  mysql_query(conn,query);//执行mysql语句
//    SQL_LOG(conn);
//    mysql_res=mysql_use_result(conn);//获取结果行集合
//    mysql_row=mysql_fetch_row(mysql_res);//获取结果的一行
//    if(atoi(mysql_row[0])==1){
//        //文件只有一个
//        bzero(query,sizeof(query));
//        sprintf(query,"update filesystem set tomb = '1' where sha1='%s';",sha1);
//        mysql_query(conn,query);
//        SQL_LOG(conn);
//        char real_path[PATH_MAX];
//        sprintf(real_path,"%s%s",rootDir,sha1);
//        int ret= remove_file(real_path);
//        if(ret==-1){
//            //给用户发删除失败的消息
//            char errorMsg[]="e:delete failed!";
//            // 发送错误信息, 如果填入NULL, 发送一个'e'报错信号
//            // 如果填入字符串, 将其作为报错信息发送给客户端
//            errorSend(netfd, errorMsg);
//        }
//        //给用户发删除成功的消息
//        // 发送成功信息'o'
//        successSend(netfd);
//    }else{
//        //文件不止一个
//        bzero(query,sizeof(query));
//        sprintf(query,"update filesystem set tomb = '1' where sha1='%s';",sha1);
//        ret=  mysql_query(conn,query);
//        SQL_LOG(conn);
//        //给用户发删除成功的消息
//        //// 发送成功信息'o'
//        successSend(netfd);
//    }
//    mysql_free_result(mysql_res);
//    return 0;
//}

//int delete_dir(MYSQL *conn,int target_id,int netfd){
//    //找到表中以目标id为pre-id的文件的id,作为新的目标id
//    MYSQL_RES *mysql_res;
//    MYSQL_ROW  mysql_row;
//    char query[4096];//构造查询语句
//    bzero(query,sizeof(query)); 
//    sprintf(query,"select id from filesystem where preid='%d';",target_id);
//    mysql_query(conn,query);
//    SQL_LOG(conn);
//    mysql_res=mysql_use_result(conn);
//    mysql_row=mysql_fetch_row(mysql_res);
//    target_id=atoi(mysql_row[0]);
//    //设置这个id的tomb为1
//    bzero(query,sizeof(query));
//    sprintf(query,"update filesystem set tomb = '1' where id='%s';",mysql_row[0]);
//    mysql_query(conn,query);
//    SQL_LOG(conn);
//    //再次判断找到的id在表中的哈希值，如果为NULL说明是目录，如果不是，说明是文件
//    bzero(query,sizeof(query));
//    sprintf(query,"select sha1 from filesystem where id='%d';",target_id);
//    mysql_query(conn,query);
//    SQL_LOG(conn);
//    mysql_res=mysql_use_result(conn);
//    mysql_row=mysql_fetch_row(mysql_res);
//    if(strcmp(mysql_row[0],"NULL")){
//        ////删除的是文件
//        delete_file(conn,mysql_row[0],netfd);
//    }else{
//        //删除的是目录
//        delete_dir(conn,target_id,netfd);
//    }
//    return 0;
//}

//int rmCmd(MYSQL *conn, int netfd, cwd_t *pcwd, cmd_t *pcmd){
//    MYSQL_RES *mysql_res;
//    MYSQL_ROW  mysql_row;
//    char real_path[1024];
//    realPath(pcwd,pcmd->argv1,real_path);//拿到表当中这个文件的路径
//    char query[4096];//构造查询语句
//    //查第一个目标id
//    sprintf(query,"select id from filesystem where path='%s' and user = '%s' and tomb = 0;",real_path,pcmd->user);
//    mysql_query(conn,query);//执行mysql语句
//    SQL_LOG(conn);
//    mysql_res=mysql_use_result(conn);//获取结果行集合
//    mysql_row=mysql_fetch_row(mysql_res);//获取结果的一行
//    int target_id=atoi(mysql_row[0]);
//    //判断是文件还是目录,查id在表中哈希值
//    bzero(query,sizeof(query)); 
//    sprintf(query,"select type from filesystem where id='%d';", target_id);
//    mysql_query(conn,query);//执行mysql语句
//    SQL_LOG(conn);
//    mysql_res=mysql_use_result(conn);//获取结果行集合
//    mysql_row=mysql_fetch_row(mysql_res);//获取结果的一行
//    if(strcmp(mysql_row[0], "f")){
//        //删除的是文件
//       // delete_file(conn,mysql_row[0],netfd);
//    }else if(strcmp(mysql_row[0], "d")){
//        //删除的是目录
//        //delete_dir(conn,target_id,netfd);
//    }
//    return 0;
//}


// 递归删除目录及里面的所有文件,rm -r
// 辅助递归函数
int recursiveRm(MYSQL *conn, char *sql, int preid)
{
    static int num = 0;
    ++num;
    printf("num = %d\n",num);
    // 查找目标id和type
    memset(sql,0,SQLLEN);
    sprintf(sql,"select id,type from filesystem where "
            "preid = %d and tomb = 0;",preid);
    mysql_query(conn,sql);
    SQL_LOG(conn);
    MYSQL_RES *res = mysql_store_result(conn);
    if(mysql_num_rows(res) <= 0){
        // 递归出口
        return 0;
    }
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(res))) {
        int id = atoi(row[0]);
        char type = row[1][0];
        // 直接删除自身
        memset(sql,0,SQLLEN);
        sprintf(sql,"update filesystem set tomb = 1 where id = %d;",id);
        mysql_query(conn,sql);
        SQL_LOG(conn);
        // 是文件就直接返回
        if(type == 'f'){
            return 0;
        }
        // 目录还需要调用递归函数
        if(recursiveRm(conn, sql, id) != 0){
            return -1;
        }
    }
    return 0;
}
// 删除指令
int rmCmd(MYSQL *conn, int netfd, cwd_t *pcwd, cmd_t *pcmd){
    MYSQL_RES *res;
    MYSQL_ROW row;
    char real_path[1024] = {0};
    realPath(pcwd,pcmd->argv1,real_path);
    printf("real_path = %s\n",real_path);
    char sql[SQLLEN];
    // 查找目标id和type
    memset(sql,0,SQLLEN);
    sprintf(sql,"select id,type from filesystem where "
            "path = '%s' and user = '%s' and tomb = 0;"
            ,real_path,pcmd->user);
    mysql_query(conn,sql);
    SQL_LOG(conn);
    res = mysql_store_result(conn);
    if(mysql_num_rows(res) <= 0){
        // 文件或目录不存在
        errorSend(netfd,NULL);
        errorSend(netfd,"文件或目录不存在!");
        return -1;
    }
    // 文件存在
    row = mysql_fetch_row(res);
    int id = atoi(row[0]);
    char type = row[1][0];
    // 直接删除自身
    memset(sql,0,SQLLEN);
    sprintf(sql,"update filesystem set tomb = 1 where id = %d;",id);
    mysql_query(conn,sql);
    SQL_LOG(conn);
    // 是文件就直接返回
    if(type == 'f'){
        successSend(netfd);
        return 0;
    }
    // 目录还需要调用递归函数
    if(recursiveRm(conn, sql, id) == 0){
        successSend(netfd);
        return 0;
    }
    else{
        errorSend(netfd,NULL);
        errorSend(netfd,"删除失败!");
        return -1;
    }
}





//mkdir操作：只可能是目录,且参数argv最后一个字符不会是‘/’
//3、获取新建文件路径
//3.1通过命令参数的第一个字符判段是用的相对地址还是绝对地址
//第一个是“/”那么肯定是绝对地址，第一个不是那么肯定是相对地址
//3.2用相对地址时新目录地址：
//3.2.1第一个字符是“.”时新文件地址：当前工作路径去掉最后一个目录名+命令参数去掉“../”
//3.2.2第一个字符是字母时，新文件地址：当前工作路径+命令参数
//3.3用绝对地址时新目录地址：命令参数
//2、新目录的id：找到最大的id，加一即新目录的id
//1、新目录的名字、新目录父目录的id
//1.1从后面往前遍历命令参数argv，倒数第一个/之后即为新目录名字
//1.2调用函数获取用户传入的路径的最后一个目录的父目录的id（即新目录父目录的id）
//4、类型为：d
//
//需要的参数：cmd_t*pcmd,
//int netfd,
//MYSQL *conn;

int cutStr(char* str1, char* str2, char div) {
    int len = strlen(str1);
    if(len >= 1 && str1[len - 1] == div) {
        str1[len - 1] = '\0';
    }
    for(int i = len - 1; i >= 0; --i) {
        if(str1[i] == div || i ==  0) {
            strncpy(str2, str1 + i + 1, len - i);
            memset(str1 + i, 0, len - i);
            break;
        }
    }
    str1[0] = '/';
    return 0;
}

int mkdirCmd(MYSQL *conn, int netfd, cwd_t *pcwd, cmd_t *pcmd){
    //新文件的名字、新文件父文件的路径和id
    char mergePath[1024] = {0};
    realPath(pcwd, pcmd->argv1, mergePath);

    char newdir[255]={0};
    cutStr(mergePath, newdir, '/');

    printf("new dir = %s\n", newdir);
    printf(".. dir = %s\n", mergePath);
    int predir_id;
    getPreid(conn, pcmd->user, mergePath, &predir_id);


    char sql[2048] = {0};
    sprintf(sql, "select id from filesystem where "
            "path = '%s' and user = '%s' and "
            "tomb = 0 and type = 'd';", mergePath, pcmd->user);
    mysql_query(conn, sql);
    SQL_LOG(conn);

    MYSQL_RES* res;
    MYSQL_ROW row;
    int fatherId = 0;
    res = mysql_store_result(conn);
    SQL_LOG(conn); 
    if(mysql_num_rows(res) != 0) {
        row = mysql_fetch_row(res);
        fatherId = atoi(row[0]);
        printf("fatherId = %d\n", fatherId);
    }
    else {
        errorSend(netfd, NULL);
        errorSend(netfd, "无法在不存在的地址创建文件夹");
        return -1;
    }
    mysql_free_result(res);
    memset(sql, 0, sizeof(sql));
    if(strcmp(mergePath, "/") == 0) {
        sprintf(sql, "insert into filesystem (filename, user, preid, path, type) values('%s', '%s', %d, '%s%s', 'd');", newdir, pcmd->user, fatherId, mergePath, newdir);
    }
    else {
        sprintf(sql, "insert into filesystem (filename, user, preid, path, type) values('%s', '%s', %d, '%s/%s', 'd');", newdir, pcmd->user, fatherId, mergePath, newdir);
    }
    printf("%s\n", sql);
    SQL_LOG(conn);
    if(mysql_query(conn, sql) == 0) {
        successSend(netfd);
    }
    else {
        errorSend(netfd, NULL);
        errorSend(netfd, "创建文件夹失败\n");
    }

    return 0;
}



//        //新文件地址：当前工作路径去掉"最后一个目录名/"+命令参数去掉“../”
//        int af_path_len=0;//after_cut_path,当前工作路径去掉"最后一个目录名/"后的长度
//        char cwd[1024]={0};
//        getPath(pcwd, cwd);
//        int cwd_len=strlen(cwd);//当前工作目录长度
//        while(pcmd->argv1[cwd_len-2]!='/'){
//            cwd_len--;
//        } 
//        cwd_len++;
//        af_path_len=cwd_len;
//        char aft_cut_path[1024]={0};//当前工作路径去掉"最后一个目录名/"后的字符串
//        sprintf(aft_cut_path,cwd,af_path_len);
//
//        char argv1_cpy[1024]={0};
//        strcpy(argv1_cpy,pcmd->argv1);
//        char *ptr = strstr(argv1_cpy, "../");//查找 "../" 的位置
//        if (ptr != NULL) {
//            ptr += 3; // 指向 "../" 后的第一个字符
//            char argv1_cpy1[1024]={0};//当前工作路径去掉"最后一个目录名/"后的字符串
//            sprintf(argv1_cpy1,"%s", ptr);
//            sprintf(newdir_path,"%s%s",aft_cut_path,argv1_cpy1);
//        }  
//    }
//    //开始向表中插入新行
//    char query[4096]={0};//构造查询语句
//    sprintf(query,"insert into filesystem "
//            "(filename,user,preid,path,tpye,tomb)"
//            "values ('%s','%s','%d','%s','%c','%d');"
//            ,newdir_name,pcmd->user,predir_id,newdir_path,'d',0);
//    mysql_query(conn,query);//执行mysql语句
//    SQL_LOG(conn);
//    //给用户发删除失败的消息
//    char errorMsg[]="e:delete failed!";
//    // 发送错误信息, 如果填入NULL, 发送一个'e'报错信号
//    // 如果填入字符串, 将其作为报错信息发送给客户端
//    errorSend(netfd, errorMsg);
//    return 0;
//}







